#include <iostream>
using namespace std;
#include <pthread.h>
#include <unistd.h>
#include <string>
#include <thread>


// 多线程的使用




#include<vector>

// 这里简单一点，直接让每个线程都执行一样的任务即可
void* thread_run(void* args){
    sleep(1);
    string name = static_cast<char*>(args);
    cout << name << "线程沉睡1s, 现在开始运行!" << endl;
    // 线程id的本质是线程控制块的起始地址，这个数字太大，把它转化为16进制
    char tid[64];
    // tid为长整型，所以需要加"l"
    snprintf(tid, sizeof(tid), "0x%lx", pthread_self());

    int cnt = 5;
    while(cnt--){
        cout << "name[" << name << "]" << ", thread["  << tid << "]" << endl;
        sleep(1);
    }
    return nullptr;
}

const int thread_num = 10;


int main(){
    vector<pthread_t> _tid_vector(thread_num, 0);
    for(int i = 0; i < 10; ++i){

        // 每个线程的名字 -> 但是这里可能会出现问题
        /* char name[64];
        snprintf(name, sizeof(name), "thread_%d", i); */

        char* name = new char[64];
        snprintf(name, 64, "thread_%d", i);

        // 创建线程
        int n = pthread_create(&_tid_vector[i], nullptr, thread_run, name);
        if(n == 0)
            cout << name << "线程创建成功!" << endl;
        else {
            cerr << name <<"线程创建失败, 将创建下一个进程" << endl;
            continue;
        }

        // 如果名字是这个写法：
        /* char name[64];
        snprintf(name, sizeof(name), "thread_%d", i); */

        // 一旦把下面的sleep(1)注释掉，就会出现问题！

        //sleep(3);
    }

    // 此时，_tid_vector中已经存储了所有的创建出来的新线程的tid，一一等待回收即可
    for(int i = 0; i < thread_num; ++i){
        int rd = pthread_join(_tid_vector[i], nullptr);
        if(rd == 0) cout << "thread_" << i << "回收成功" << endl;
        else cerr << "thread_" << i << "回收失败" << endl;
    }

    return 0;
}












// 线程局部存储

/* __thread int cnt = 1;

void* thread_1_run(void* args){
    string name = static_cast<char*>(args);
    while(1){
        cout << name << "线程修改cnt变量, cnt : " << cnt << endl;
        ++cnt;
        sleep(1);
    }
    return nullptr;
}

void* thread_2_run(void* args){
    string name = static_cast<char*>(args);
    while(1){
        cout << name << "线程查看cnt变量, cnt : " << cnt << endl;
        sleep(1);
    }
    return nullptr;
}

int main(){
    pthread_t tid1, tid2;
    pthread_create(&tid1, nullptr, thread_1_run, (char*)"thread_1");
    pthread_create(&tid2, nullptr, thread_2_run, (char*)"thread_2");

    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);
    return 0;
} */










// 验证传参和返回值的任意性
/* class Task{
public:
    Task(int a = 0, int b = 0)
        :_a(a), _b(b)
    {}

    ~Task(){}

    int Execute(){
        return _a + _b;
    }

private:
    int _a;
    int _b;
};

class Result{
public:
    Result(int res = 0)
        :_res(res)
    {}

    ~Result(){}

    int GetRes() const{
        return _res;
    }
private:
    int _res;
};


void* thread_1_run(void* args){
    // 此时该线程知道，主线程传入的是Task*
    Task* pt = static_cast<Task*>(args);
    Result* res = new Result(pt->Execute());

    // 新线程只跑5s
    int cnt = 5;
    while(cnt--){
        cout << "i am a new thread" << " ,线程id : " << pthread_self() << endl;
        sleep(1);
    }

    return res;
}



int main(){
    // 使用堆区上的，使用栈区上也可以，但是还是用堆区上的规范一些 -> 讲解原理后明白
    Task* ptask = new Task(10, 20);
    pthread_t tid;

    // 把类传入
    pthread_create(&tid, nullptr, thread_1_run, ptask);

    cout << "主线程等待回收新线程" << endl;

    void* res = nullptr;
    pthread_join(tid, &res);
    // 此时就把Result类返回了

    Result* pr = static_cast<Result*>(res);
    cout << "任务返回结果 : " << pr->GetRes() << endl;


	delete ptask;
	delete pr;

    return 0;
} */










// 综合使用接口

/* void* thread_1_run(void* args){

    //这里也可以直接从线程中分离 ，效果和主线程中分离一样
    //pthread_detach(pthread_self()); //这里就不重复展示了


    string name = static_cast<char*>(args);
    
    // 新线程只跑5s
    int cnt = 5;
    while(cnt--){
        cout << "i am a new thread, name is " << name << endl;
        cout << name << "线程id : " << pthread_self();
        sleep(1);
    }

    // 直接让线程终止，把3强制转化为void*当作pthread_exit的参数
    cout << name << "线程结束" << endl;
    pthread_exit((void*)3);

    return (void*)0;
}



int main(){
    //创建一个线程 -> pthread_create
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_1_run, (char*)"thread_1");
    //新线程执行thread_1_run，主线程继续往下执行

    //打印主线程的线程id

    // 分离线程thread_1
    cout << "分离线程thread_1" << endl;
    pthread_detach(tid);

    int cnt = 10;
    while(cnt--){
        cout << "main thread id : " << pthread_self() << endl;
        sleep(1);
    }
    
    // pthread_join的第二个参数是void**，是一个输出型参数！  
    // 就是把线程退出返回的变量以void* 返回，但是为了能够接收到，就只能通过传址调用来进行修改外界变量！
    void* ret;
    int n = pthread_join(tid, &ret);
    if(!n) cout << "thread_1 退出结果" << (long long)ret << endl;
    else cout << "thread_1 is detached, cannot recycle!" << endl;
    return 0;
} */

// 注意，线程中都有变量cnt，这个是属于每个线程的栈区的，互不影响！！！

















// 使用原生线程库 -> 演示线程内存泄露 
// 但是ubuntu 22.04演示不出来

/* void* thread_1_run(void* args){
    string name = static_cast<char*>(args);
    
    // 新线程只跑5s
    int cnt = 5;
    while(cnt--){
        cout << "i am a new thread, name is " << name << endl;
        sleep(1);
    }
    cout << name << "线程结束" << endl;
    pthread_exit((void*)0);
    return (void*)0;
}

int main(){
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_1_run, (char*)"thread_1");

    // 让主线程一直不退出
    while(1){
        cout << "main process" << endl;
        sleep(1);
    }
    return 0;
}
 */






// 使用c++11给出的线程库

/* void* Thread_1_run(void* args){
    string name = static_cast<char*>(args);
    cout << "i am a new thread, name is " << name << endl;
    sleep(1);
    return (void*)0;
}

void* Thread_1_run_2(void* args){
    string name = static_cast<char*>(args);
    cout << "i am a new thread, name is " << name << endl;
    cout << "sleep 5 seconds" << endl;
    sleep(5);
    // 使用exit 退出
    exit(1);
    cout << "hello" << endl;
    return (void*)0;
}



int main(){
    thread t(Thread_1_run_2, (char*)"thread_1");

    int cnt = 5;
    while(1){//cnt--
        cout << "main process" << endl;
        sleep(1);
    }
    t.join();
    return 0;
} */
















// 用于验证线程概念的结论：
/* int flag = 100;

void* newThreadRun(void* args){
    string tmp = (char*)args;   
    while(1){
        cout << "new thread : my name is " << tmp << endl;
        ++flag;
        // 故意让这个线程搞出异常！！！
        if(flag == 105) flag /= 0;
        sleep(1);
    }

    //先随便返回一个值
    return (void*)0;
}

int main(){
    pthread_t tid;
    //创建一个线程，让该线程执行newThreadRun函数
    pthread_create(&tid, nullptr, newThreadRun, (char*)"thread_1");

    while(1){
        cout << "main thread..." << ", flag is " << flag << endl;
        sleep(1);
    }
    return 0;
} */

